/* $Id: scanner.ll 44 2008-10-23 09:03:19Z tb $ -*- mode: c++ -*- */
/** \file scanner.ll Define the example Flex lexical scanner */

D                       [0-9]
L                       [a-zA-Z_]
H                       [a-fA-F0-9]
E                       [Ee][+-]?{D}+
FS                      (f|F|l|L)
IS                      (u|U|l|L)*

%{ /*** C/C++ Declarations ***/

#include <string>

#include "scanner.h"
#include "parser.h"

/* import the parser's token type into a local typedef */
typedef RUN::Parser::token token;
typedef RUN::Parser::token_type token_type;

/* By default yylex returns int, we use token_type. Unfortunately yyterminate
 * by default returns 0, which is not of token_type. */
#define yyterminate() return token::END

/* This disables inclusion of unistd.h, which is not available under Visual C++
 * on Win32. The C++ scanner uses STL streams instead. */
#define YY_NO_UNISTD_H

%}

/*** Flex Declarations and Options ***/

/* enable c++ scanner class generation */
%option c++

/* change the name of the scanner class. results in "ExampleFlexLexer" */
%option prefix="RUN"

/* the manual says "somewhat more optimized" */
%option batch

/* enable scanner to generate debug output. disable this for release
 * versions. */
%option debug

/* no support for include files is planned */
%option yywrap nounput 

/* enables the use of start condition stacks */
%option stack

%x COMMENT

/* The following paragraph suffices to track locations accurately. Each time
 * yylex is invoked, the begin position is moved onto the end position. */
%{
#define YY_USER_ACTION  yylloc->columns(yyleng);
%}

%% /*** Regular Expressions Part ***/

 /* code to place at the beginning of yylex() */
%{
    // reset location
    yylloc->step();
%}

 /*** BEGIN EXAMPLE - Change the example lexer rules below ***/

 /* comments */
"/*" { BEGIN(COMMENT); }
<COMMENT>"*/" { BEGIN(INITIAL); }
<COMMENT>([^*]|\n)+|. { yylloc->lines(yyleng); yylloc->step(); }
<COMMENT><<EOF>> { printf("%d: Unterminated comment\n", yylineno); yyterminate(); }
 
"//".*\n                { yylloc->lines(yyleng); yylloc->step(); }
 
"break"                 { return token::BREAK; }

"continue"              { return token::CONTINUE; }

"do"                    { return token::DO; }

"else"                  { return token::ELSE; }

"for"                   { return token::FOR; }

"if"                    { return token::IF; }

"return"                { return token::RETURN; }

"class"                 { return token::CLASS; }
"method"                { return token::METHOD; }
 /*** "this"                  { return token::THIS; } ***/
"new"                   { return token::NEW; }
"var"                   { return token::VAR; }
"function"              { return token::FUNCTION; }


"while"                 { return token::WHILE; }

{L}({L}|{D})*           { yylval->stringVal = new std::string(yytext, yyleng);
							return token::IDENTIFIER; }

{D}+               { yylval->integerVal = atoi(yytext);
                     return token::CONSTANT; }

\"(\\.|[^\\"])*\"     { yylval->stringVal = new std::string(yytext, yyleng);
                          return token::STRING_LITERAL; }

">>="                   { return token::RIGHT_ASSIGN; }
"<<="                   { return token::LEFT_ASSIGN; }
"+="                    { return token::ADD_ASSIGN; }
"-="                    { return token::SUB_ASSIGN; }
"*="                    { return token::MUL_ASSIGN; }
"/="                    { return token::DIV_ASSIGN; }
"%="                    { return token::MOD_ASSIGN; }
"&="                    { return token::AND_ASSIGN; }
"^="                    { return token::XOR_ASSIGN; }
"|="                    { return token::OR_ASSIGN; }
">>"                    { return token::RIGHT_OP; }
"<<"                    { return token::LEFT_OP; }
"++"                    { return token::INC_OP; }
"--"                    { return token::DEC_OP; }

"&&"                    { return token::AND_OP; }
"||"                    { return token::OR_OP; }
"<="                    { return token::LE_OP; }
">="                    { return token::GE_OP; }
"=="                    { return token::EQ_OP; }
"!="                    { return token::NE_OP; }
 /**********************************************/
";"                     { return token::SEMICOLON; }
":"                     { return token::COLON; }
"{"              { return token::LBRACE; }
"}"              { return token::RBRACE; }
","                     { return token::COMMA; }

"="                     { return token::ASSIGN; }
"("                     { return token::LPAREN; }
")"                     { return token::RPAREN; }
"["              { return token::LBRACKET; }
"]"              { return token::RBRACKET; }
"."                     { return token::DOT; }
"&"                     { return token::BIT_AND_OP; }
"!"                     { return token::NOT_OP; }
"~"                     { return token::NEG_OP; }
"-"                     { return token::MINUS_OP; }
"+"                     { return token::PLUS_OP; }
"*"                     { return token::MUL_OP; }
"/"                     { return token::DIV_OP; }
"%"                     { return token::MOD_OP; }
"<"                     { return token::LT_OP; }
">"                     { return token::GT_OP; }
"^"                     { return token::XOR_OP; }
"|"                     { return token::BIT_OR_OP; }


[ \t\v\f\r\a]             { yylloc->step(); }

 /********************************************************/

 /* gobble up end-of-lines */
\n {
    yylloc->lines(yyleng); yylloc->step();
    //return token::EOL;
}

 /* pass all other characters up to bison */
. {
    return static_cast<token_type>(*yytext);
}

 /*** END EXAMPLE - Change the example lexer rules above ***/

%% /*** Additional Code ***/

namespace RUN {

Scanner::Scanner(std::istream* in,
		 std::ostream* out)
    : RUNFlexLexer(in, out)
{
}

Scanner::~Scanner()
{
}

void Scanner::set_debug(bool b)
{
    yy_flex_debug = b;
}

}

/* This implementation of ExampleFlexLexer::yylex() is required to fill the
 * vtable of the class ExampleFlexLexer. We define the scanner's main yylex
 * function via YY_DECL to reside in the Scanner class instead. */

#ifdef yylex
#undef yylex
#endif

int RUNFlexLexer::yylex()
{
    std::cerr << "in FlexLexer::yylex() !" << std::endl;
    return 0;
}

/* When the scanner receives an end-of-file indication from YY_INPUT, it then
 * checks the yywrap() function. If yywrap() returns false (zero), then it is
 * assumed that the function has gone ahead and set up `yyin' to point to
 * another input file, and scanning continues. If it returns true (non-zero),
 * then the scanner terminates, returning 0 to its caller. */

int RUNFlexLexer::yywrap()
{
    return 1;
}
